package oa.hleast.xswl.service.chat.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import oa.hleast.common.upload.component.MinIOService;
import oa.hleast.common.utils.JsonUtil;
import oa.hleast.xswl.common.config.WebSocketConfig;
import oa.hleast.xswl.common.constant.ChatDateEnum;
import oa.hleast.xswl.common.constant.ChatterTypeEnum;
import oa.hleast.xswl.controller.ws.IWebSocket;
import oa.hleast.xswl.mapper.chat.ChatAutoReplyMapper;
import oa.hleast.xswl.mapper.chat.ChatMessageLogMapper;
import oa.hleast.xswl.pojo.domain.chat.CmsChatAutoReply;
import oa.hleast.xswl.pojo.domain.chat.CmsChatMessageLog;
import oa.hleast.xswl.pojo.domain.chat.CmsChatSession;
import oa.hleast.xswl.pojo.dto.UmsUserDto;
import oa.hleast.xswl.pojo.form.chat.ChatForm;
import oa.hleast.xswl.pojo.vo.chat.CmsChatAutoReplyVo;
import oa.hleast.xswl.service.IUmsUserService;
import oa.hleast.xswl.service.chat.AiService;
import oa.hleast.xswl.service.chat.CmsChatSessionService;
import oa.hleast.xswl.service.chat.IChatAutoReplyService;
import oa.hleast.xswl.service.chat.IChatMessageLogService;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.websocket.Session;
import java.io.IOException;
import java.util.List;
import java.util.Objects;

/**
 * @author 00204
 */
@Service
@Slf4j
@Transactional
@AllArgsConstructor
public class WebSocketClientService implements IWebSocket {

    private final IChatMessageLogService iChatMessageLogService;
    private final CmsChatSessionService cmsChatSessionService;
    private final IUmsUserService umsUserService;
    private final AiService aiService;
    private final ChatAutoReplyMapper chatAutoReplyMapper;
    private final IChatAutoReplyService chatAutoReplyService;
    private final ChatMessageLogMapper chatMessageLogMapper;

    @Override
    public void onOpen(String userId, Session session) {
        log.info("现在来连接的客户端用户id：" + userId);

        //查询所有客服发送未读消息
        List<CmsChatMessageLog> listMsg = iChatMessageLogService.list(new LambdaQueryWrapper<CmsChatMessageLog>()
                .eq(CmsChatMessageLog::getSendStatus, 1)
                .eq(CmsChatMessageLog::getChatterType, "SYS")
                .eq(CmsChatMessageLog::getChatId, Long.parseLong(userId)));
        if (listMsg.size() > 0) {
            session.getAsyncRemote().sendText(JsonUtil.obj2String(listMsg));
        }
        UmsUserDto userResult = null;
        try {
            userResult = umsUserService.getUserDtoById(Long.parseLong(userId));
        } catch (NumberFormatException e) {
            log.error("获取用户信息失败", e);
        }
        List<CmsChatMessageLog> list = iChatMessageLogService.list(new LambdaQueryWrapper<CmsChatMessageLog>()
                .eq(CmsChatMessageLog::getSendStatus, 1)
                .eq(CmsChatMessageLog::getChatterType, "USER")
                .eq(CmsChatMessageLog::getChatId, Long.parseLong(userId)));
        CmsChatSession byId = cmsChatSessionService.getById(Long.parseLong(userId));
        if (byId != null) {
            cmsChatSessionService.saveOrUpdate(CmsChatSession.builder()
                    .id(Long.parseLong(userId))
                    .userId(Long.parseLong(userId))
                    .userName(userResult.getNickname())
                    .unreadNum(list.size())
                    .build());
        } else {
            cmsChatSessionService.save(CmsChatSession.builder()
                    .id(Long.parseLong(userId))
                    .userId(Long.parseLong(userId))
                    .replyStatus(CmsChatSession.REPLY_STATUS_AUTO)
                    .userName(userResult.getNickname())
                    .unreadNum(list.size())
                    .build());
        }

        //把自己的信息加入到map当中去
        WebSocketConfig.clients.put(userId, session);

    }

    @Override
    public void handleMessage(String userId, String message, Session session, String messageType, String assetUrl) throws IOException {

        log.info("客户端发送消息：" + message + "客户端的id是：" + userId);
        //判断回复类型类型
        Integer replyStatus = cmsChatSessionService.getById(Long.parseLong(userId)).getReplyStatus();
        //修改回复状态
        LambdaUpdateWrapper<CmsChatSession> updateWrapper = new LambdaUpdateWrapper<CmsChatSession>().eq(CmsChatSession::getId, Long.parseLong(userId));
        if (replyStatus.equals(CmsChatSession.REPLY_STATUS_AUTO)) {
            if (message.equals("人工客服")) {
                CmsChatMessageLog msg = CmsChatMessageLog.builder()
                        .chatId(Long.parseLong(userId))
                        .chatterId(Long.parseLong(userId))
                        .chatterType(ChatterTypeEnum.SYS.name())
                        .content("正在为您转接人工客服，请稍等。")
                        .type(ChatDateEnum.TXT.name())
                        .build();
                session.getAsyncRemote().sendText(JsonUtil.obj2String(msg));

                if (WebSocketConfig.server.containsKey(userId)) {
                    //客服在线
                    sendMessageTo(message, userId);
                    //将消息存储至数据库
                    iChatMessageLogService.save(CmsChatMessageLog.builder()
                            .chatId(Long.parseLong(userId))
                            .chatterId(Long.parseLong(userId))
                            .chatterType(ChatterTypeEnum.USER.name())
                            .content(message)
                            .assetUrl(assetUrl)
                            .type(messageType)
                            .sendStatus(CmsChatMessageLog.SEND_STATUS_SUCCESS)
                            .build());
                } else {
                    //将消息存储至数据库
                    iChatMessageLogService.save(CmsChatMessageLog.builder()
                            .chatId(Long.parseLong(userId))
                            .chatterId(Long.parseLong(userId))
                            .chatterType(ChatterTypeEnum.USER.name())
                            .content(message)
                            .assetUrl(assetUrl)
                            .type(messageType)
                            .sendStatus(CmsChatMessageLog.SEND_STATUS_FAIL)
                            .build());
                }
                updateWrapper.set(CmsChatSession::getReplyStatus, CmsChatSession.REPLY_STATUS_WAIT);
                //将消息存储至数据库
                iChatMessageLogService.save(msg);

            } else {
                //智能客服
                ChatForm form = ChatForm.builder().distinguishValue(message).type(ChatDateEnum.TXT.name()).build();
                CmsChatMessageLog chat = chat(Long.parseLong(userId), form, true);
                session.getAsyncRemote().sendText(JsonUtil.obj2String(chat));
            }
        } else {

            if (WebSocketConfig.server.containsKey(userId)) {
                CmsChatMessageLog msg = CmsChatMessageLog.builder()
                        .chatId(Long.parseLong(userId))
                        .chatterId(Long.parseLong(userId))
                        .chatterType(ChatterTypeEnum.USER.name())
                        .content(message)
                        .assetUrl(assetUrl)
                        .type(messageType)
                        .sendStatus(CmsChatMessageLog.SEND_STATUS_SUCCESS)
                        .build();
                //将消息存储至数据库
                iChatMessageLogService.save(msg);
                sendMessageTo(JsonUtil.obj2String(msg), userId);
                updateWrapper.set(CmsChatSession::getReplyStatus, CmsChatSession.REPLY_STATUS_ARTI);
            } else {
                //将消息存储至数据库
                iChatMessageLogService.save(CmsChatMessageLog.builder()
                        .chatId(Long.parseLong(userId))
                        .chatterId(Long.parseLong(userId))
                        .chatterType(ChatterTypeEnum.USER.name())
                        .content(message)
                        .assetUrl(assetUrl)
                        .type(messageType)
                        .sendStatus(CmsChatMessageLog.SEND_STATUS_FAIL)
                        .build());
                updateWrapper.set(CmsChatSession::getReplyStatus, CmsChatSession.REPLY_STATUS_WAIT);
            }
        }
        //更新未读消息数量
        List<CmsChatMessageLog> list = iChatMessageLogService.list(new LambdaQueryWrapper<CmsChatMessageLog>()
                .eq(CmsChatMessageLog::getSendStatus, CmsChatMessageLog.SEND_STATUS_FAIL)
                .eq(CmsChatMessageLog::getChatterType, "USER")
                .eq(CmsChatMessageLog::getChatId, Long.parseLong(userId)));
        updateWrapper.set(CmsChatSession::getUnreadNum, list.size());
        cmsChatSessionService.update(updateWrapper);
    }


    public void sendMessageTo(String message, String userId) throws IOException {
        WebSocketConfig.server.get(userId).getBasicRemote().sendText(message);
    }

    public void sendMessageAll(String message) {
        for (Session item : WebSocketConfig.server.values()) {
            item.getAsyncRemote().sendText(message);
        }
    }

    private final MinIOService minIOService;

    public String handleVoice(Long userId, ChatForm form) throws IOException {
        // 1， 语音识别
        String distinguishValue = aiService.distinguish(form.getFile());
        log.info("语音识别结果 distinguishValue ={}", distinguishValue);
        // 2， 语音上传  音频
        String suffix = Objects.requireNonNull(form.getFile().getOriginalFilename()).substring(form.getFile().getOriginalFilename().lastIndexOf(".") + 1);
        String objectName = IdUtil.simpleUUID() + "." + suffix;
        String path = null;
        try {
            path = minIOService.putObject("xswl-dev-audio", objectName, form.getFile().getInputStream());
        } catch (Exception e) {
            e.printStackTrace();
            log.info("e = {}", e, e);
        }

//        Result<String> audio = memberFeignService.uploadForService(form.getFile(), "audio");
        log.info("音频上传地址 audio = {}", path);
        //  附件地址
        String assetUrl = path;
        System.out.println("clients: " + WebSocketConfig.clients.keySet());
        handleMessage(String.valueOf(userId), distinguishValue, WebSocketConfig.clients.get(""+userId), ChatDateEnum.VOICE.name(), assetUrl);
        return assetUrl;
    }

    public CmsChatMessageLog chat(Long userId, ChatForm form, Boolean save) {
        String distinguishValue = form.getDistinguishValue();
        String type = form.getType();
        //  附件地址
        String assetUrl = null;

        // 3， 匹配回复
        CmsChatAutoReply chatAutoReply = chatAutoReplyMapper.matchingReply(distinguishValue);
        if (ObjectUtils.isEmpty(chatAutoReply)) {
            chatAutoReply = getDefaultReply();
        }

        // 4, 保存记录 2条记录 用户消息 系统回复消息
        //判断消息类型，如果为智能参谋则不保存
        if (save) {
            chatMessageLogMapper.insert(CmsChatMessageLog.builder()
                    .chatId(userId)
                    .chatterId(userId)
                    .chatterType(ChatterTypeEnum.USER.name())
                    .content(distinguishValue)
                    .type(form.getType())
                    .assetUrl(assetUrl)
                    .voiceDuration(form.getVoiceDuration())
                    .build());
        }
        CmsChatMessageLog msg = CmsChatMessageLog.builder()
                .chatId(userId)
                .chatterId(0L)
                .chatterType(ChatterTypeEnum.SYS.name())
                .content(chatAutoReply.getReply())
                .type(ChatDateEnum.TXT.name())
                .build();
        chatMessageLogMapper.insert(msg);

        return msg;
    }


    private CmsChatAutoReplyVo conversionToReplyVo(CmsChatAutoReply pojo) {
        CmsChatAutoReplyVo vo = new CmsChatAutoReplyVo();
        BeanUtil.copyProperties(pojo, vo);
        return vo;
    }

    public CmsChatAutoReply getDefaultReply() {

        return CmsChatAutoReply.builder().priority((byte)0).reply("<p>你好，欢迎来到萧山文旅</p>").build();
//        CmsChatAutoReply chatAutoReply = chatAutoReplyService.getById(1L);
//        if (ObjectUtils.isEmpty(chatAutoReply)) {
//            log.error("没有找到默认匹配值");
//            return null;
//        }
//        return chatAutoReply;
    }

}
